import datetime
import math
import os
import sys
import time
import traceback

# 将工程目录加入包扫描
currPath = os.path.abspath(os.path.dirname(__file__))
srcPath = os.path.split(currPath)[0]
rootPath = os.path.split(srcPath)[0]
projectPath = os.path.split(rootPath)[0]
sys.path.append(projectPath)

from src.db.FCDB import FCDB
from src.utils import CommonUtils
from src.utils.CommonUtils import cleanScreen
from src.utils.LogUtils import Logger
from tqdm import tqdm
from src.db.LocalDb import LocalDb


class CalcSecuritiesDuration:
    """
    计算债券存续期
    """

    def __init__(self, logger, localDb, fcdb):
        self.logger = logger
        self.localDb = localDb
        self.fcdb = fcdb
        self.size = 1000

    def __loadSecurities__(self):
        sql = """
            SELECT secode, remaining_time FROM deb_debenture_base 
            where 
            remaining_time is not null or expire_date > CURRENT_DATE()
        """
        return self.localDb.Query(sql)

    # 加载财汇估值数据
    def __loadQqqtCbestimate_(self, tradeDate, secodes):
        sql = """
            SELECT SECODE, TERMTOMATURITY FROM (
                SELECT SECODE, TERMTOMATURITY, ROW_NUMBER() OVER(partition BY secode ORDER BY VALUATIONTYPE ASC )  AS `no`
                FROM tq_qt_cbestimate 
                WHERE TRADEDATE = %s
                AND SECODE in %s
            ) t WHERE t.`no`= 1
        """
        return self.fcdb.Query(sql, (tradeDate, secodes))

    # 更新已过期的
    def __update__(self, remainingTime, secode):
        sql = """
            update deb_debenture_base set remaining_time = %s where secode = %s
        """
        return self.localDb.ExecNoneQuery(sql, (remainingTime, secode))

    def calc(self):

        # 计算日期
        tradeDate = CommonUtils.DateToStr(datetime.date.today() - datetime.timedelta(days=1))
        self.logger.info("计算基准交易日：%s" % tradeDate)

        # 加载全部债券
        self.logger.info("加载全部债券")
        securities = self.__loadSecurities__()
        self.logger.info("加载全部债券 %d" % len(securities))

        total = len(securities)
        pages = math.ceil(total / self.size)

        for page in tqdm(range(pages), desc="pages", file=sys.stdout):
            start = page * self.size
            end = start + self.size
            subList = securities[start:end]
            secodes = list(d["secode"] for d in subList)

            # 拉取财汇估值数据
            cbestimateDatas = self.__loadQqqtCbestimate_(tradeDate=tradeDate, secodes=secodes)
            cbestimateDatas = {d["SECODE"]: d["TERMTOMATURITY"] for d in cbestimateDatas}

            # 逐个赋值
            for d in subList:
                secode = d["secode"]
                remaining_time = cbestimateDatas[secode] if secode in cbestimateDatas.keys() else None
                self.__update__(remaining_time, secode)


def __main__():
    logger = Logger()
    try:
        t = time.perf_counter()
        localDb = LocalDb(logSql=False, autocommit=True)
        fcdb = FCDB(logSql=False, autocommit=True)
        cleanScreen()
        calc = CalcSecuritiesDuration(logger=logger, localDb=localDb, fcdb=fcdb)
        # 计算结果
        calc.calc()
        cast = (time.perf_counter() - t)
        m = math.floor(cast / 60)
        s = cast - m * 60
        logger.info('计算结束 %s 总耗时: %d分%.3f秒' % (datetime.datetime.now(), m, s))
    except Exception as e:
        traceback.print_exc()
        logger.error("程序发生异常")
        logger.error(e)


# 程序入口
if __name__ == "__main__":
    __main__()
